#region Copyright and Licensing Notice
// Copyright (C) 2011 Steven Bosnick
// 
// This program is open source software; you can redistribute it 
// and/or modifiy it under the terms of the Eclipse Public License,
// version 1.0.
// 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A 
// PARTICULAR PURPOSE. See the Eclipse Public License for more
// details.
// 
// You should have received a copy of the Eclipse Public License 
// along with this program; if not, you can find a copy at
// "http://www.opensource.org/licenses/eclipse-1.0.php".
#endregion
using System;
using System.IO;
using System.Threading;
using Autofac;
using Autofac.Core;
using BitwiseOre.SharedMemory.Autofac;
using BitwiseOre.SharedMemory.Context;

namespace BitwiseOre.SharedMemory
{
    /// <summary>
    /// Manages the context for shared memory listeners, factories, and
    /// streams.
    /// </summary>
    public sealed class SharedMemoryContext
    {
        private static readonly IContainer Container;
        private readonly ILifetimeScope _lifetimeScope;

        static SharedMemoryContext()
        {
            Container = new Bootstrapper<SharedMemoryModule>().Build();
        }

        /// <summary>
        /// Constructs a new <see cref="SharedMemoryContext"/>
        /// </summary>
        public SharedMemoryContext()
        {
            _lifetimeScope = Container.BeginLifetimeScope(typeof (SharedMemoryContext));
        }

        internal SharedMemoryListener CreateListener(string name)
        {
            if (name == null) throw new ArgumentNullException("name");

            return CreateRootWithStreamFactory<SharedMemoryListener>(name, WrapListenerCreationException,
                                                                     SharedObjectStatus.CreateNew);
        }

        internal SharedMemoryFactory CreateFactory(string name)
        {
            if (name == null) throw new ArgumentNullException("name");

            return CreateRootWithStreamFactory<SharedMemoryFactory>(name, WrapFactoryCreationException,
                                                                    SharedObjectStatus.OpenExisting);
        }

        private T CreateRootWithStreamFactory<T>(
            string name,
            Func<DependencyResolutionException, Exception> wrapException,
            SharedObjectStatus streamStatus)
        {
            Func<Guid, SharedMemoryStream> streamfactory =
                guid => _lifetimeScope.ResolveRoot<SharedMemoryStream>(
                    _ => null,
                    new NamedParameter("guid", guid),
                    new NamedParameter("status", streamStatus));

            return _lifetimeScope.ResolveRoot<T>(
                wrapException, 
                new NamedParameter("name", name),
                new NamedParameter("streamFactory", streamfactory));
        }

        private static Exception WrapListenerCreationException(DependencyResolutionException exception)
        {
            if (exception.InnerException is IOException)
            {
                return new IOException(exception.InnerException.Message, exception);
            }
            if (exception.InnerException is InvalidOperationException)
            {
                return new InvalidOperationException(exception.InnerException.Message, exception);
            }
            return null;
        }

        private static Exception WrapFactoryCreationException(DependencyResolutionException exception)
        {
            if (exception.InnerException is FileNotFoundException)
            {
                return new FileNotFoundException(exception.InnerException.Message, exception);
            }
            if (exception.InnerException is WaitHandleCannotBeOpenedException)
            {
                return new WaitHandleCannotBeOpenedException(exception.InnerException.Message, exception);
            }
            return null;
        }

        ///<summary>
        /// The context within which a new <see cref="SharedMemoryListener"/> is created.
        ///</summary>
        public IListenerContext ListenerContext
        {
            get { return _lifetimeScope.Resolve<IListenerContext>(); }
        }

        /// <summary>
        /// The context within which a new <see cref="SharedMemoryStream"/> is created.
        /// </summary>
        public IStreamContext StreamContext
        {
            get { return _lifetimeScope.Resolve<IStreamContext>(); }
        }
    }
}